using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Data.SQLite;

namespace GPSNav.NET
{
	public class GpsDataDigest
	{
		public GpsDataDigest()
		{
			Initialize();
		}


		Dictionary<string, int> lods = new Dictionary<string, int>();
		Dictionary<string, int> wTypes = new Dictionary<string, int>();


		Dictionary<string, int> tags = new Dictionary<string, int>();
		Dictionary<string, Dictionary<string, int>> tagsv = new Dictionary<string, Dictionary<string, int>>();
		private void Initialize()
		{


			/*

			tags.Add("highway", 1);
			tags.Add("junction", 2);
			tags.Add("traffic_calming", 3);
			tags.Add("service", 4);
			tags.Add("ref", 5);
			tags.Add("name", 6);
			tags.Add("oneway", 7);
			tags.Add("access", 8);
			
			
			tagsv.Add("highway", new Dictionary<string, int>());
			tagsv ["highway"].Add("motorway", 1);
			tagsv ["highway"].Add("motorway_link", 2);
			tagsv ["highway"].Add("trunk", 3);
			tagsv ["highway"].Add("trunk_link", 4);
			tagsv ["highway"].Add("primary", 5);
			tagsv ["highway"].Add("primary_link", 6);
			tagsv ["highway"].Add("secondary", 7);
			tagsv ["highway"].Add("tertiary", 8);
			tagsv ["highway"].Add("unclassified", 9);
			tagsv ["highway"].Add("road", 10);
			tagsv ["highway"].Add("residential", 11);
			tagsv ["highway"].Add("living_street", 12);
			tagsv ["highway"].Add("service", 13);
			tagsv ["highway"].Add("track", 14);
			tagsv ["highway"].Add("pedestrian", 15);
			tagsv ["highway"].Add("services", 16);
			tagsv ["highway"].Add("bus_guideway", 17);
			tagsv ["highway"].Add("path", 18);
			tagsv ["highway"].Add("cycleway", 19);
			tagsv ["highway"].Add("footway", 20);
			tagsv ["highway"].Add("bridleway", 21);
			tagsv ["highway"].Add("byway", 22);
			tagsv ["highway"].Add("steps", 23);
			tagsv ["highway"].Add("mini_roundabout", 24);
			tagsv ["highway"].Add("stop", 25);
			tagsv ["highway"].Add("traffic_signals", 26);
			tagsv ["highway"].Add("crossing", 27);
			tagsv ["highway"].Add("gate", 28);
			tagsv ["highway"].Add("stile", 29);
			tagsv ["highway"].Add("cattle_grid", 30);
			tagsv ["highway"].Add("toll_booth", 31);
			tagsv ["highway"].Add("incline", 32);
			tagsv ["highway"].Add("incline_steep", 33);
			tagsv ["highway"].Add("ford", 34);
			tagsv ["highway"].Add("bus_stop", 35);
			tagsv ["highway"].Add("turning_circle", 36);
			tagsv ["highway"].Add("construction", 37);
			tagsv ["highway"].Add("emergency_access_point", 38);
			tagsv ["highway"].Add("motorway_junction", 39);



			tagsv.Add("junction", new Dictionary<string, int>());
			tagsv ["junction"].Add("roundabout", 40);
			//tagsv ["junction"].Add("", 1);

			tagsv.Add("traffic_calming", new Dictionary<string, int>());

			tagsv ["traffic_calming"].Add("yes", 41);
			tagsv ["traffic_calming"].Add("bump", 42);
			tagsv ["traffic_calming"].Add("chicane", 43);
			tagsv ["traffic_calming"].Add("cushion", 44);
			tagsv ["traffic_calming"].Add("hump", 45);
			tagsv ["traffic_calming"].Add("rumble_strip", 46);
			tagsv ["traffic_calming"].Add("table", 47);
			tagsv ["traffic_calming"].Add("choker", 48);

			tagsv.Add("service", new Dictionary<string, int>());

			tagsv ["service"].Add("parking_aisle", 49);
			tagsv ["service"].Add("driveway", 50);
			tagsv ["service"].Add("alley", 51);


			tagsv.Add("oneway", new Dictionary<string, int>());
			tagsv ["oneway"].Add("yes", 52);

*/






			wTypes.Add("motorway", 1);
			wTypes.Add("motorway_link", 2);
			wTypes.Add("trunk", 3);
			wTypes.Add("trunk_link", 4);
			wTypes.Add("primary", 5);
			wTypes.Add("primary_link", 6);
			wTypes.Add("secondary", 7);
			wTypes.Add("tertiary", 8);
			wTypes.Add("unclassified", 9);
			wTypes.Add("road", 10);
			wTypes.Add("residential", 11);
			wTypes.Add("living_street", 12);
			wTypes.Add("service", 13);
			wTypes.Add("track", 14);
			wTypes.Add("pedestrian", 15);
			wTypes.Add("services", 16);
			wTypes.Add("bus_guideway", 17);

			lods.Add("motorway", 1);
			lods.Add("motorway_link", 1);
			lods.Add("trunk", 2);
			lods.Add("trunk_link", 2);
			lods.Add("primary", 3);
			lods.Add("primary_link", 3);
			lods.Add("secondary", 4);
			lods.Add("tertiary", 5);
			lods.Add("unclassified", 10);
			lods.Add("road", 6);
			lods.Add("residential", 7);
			lods.Add("living_street", 8);
			lods.Add("service", 9);
			lods.Add("track", 10);
			lods.Add("pedestrian", 11);
			lods.Add("services", 12);
			lods.Add("bus_guideway", 13);






		}



	





		public void DigestXmlDb(string source, string destPrefix)
		{

			Console.WriteLine("DigestXmlDb");
			SQLiteConnection sqlConnection;
			SQLiteCommand sqlCommand;
			SQLiteCommand sqlCommand2;
			SQLiteCommand sqlCommand3;
			SQLiteCommand sqlCommand4;
			SQLiteCommand sqlCommand5;

			sqlConnection = new SQLiteConnection(@"Data Source=G:\gps\gps.sqlite;Pooling=true;FailIfMissing=false");
			sqlCommand = new SQLiteCommand(sqlConnection);
			sqlCommand.CommandType = System.Data.CommandType.Text;
			sqlConnection.Open();

			sqlCommand.CommandText = "PRAGMA synchronous = OFF;";
			sqlCommand.ExecuteNonQuery();

			SQLiteTransaction t = sqlConnection.BeginTransaction();



			sqlCommand.CommandText = "PRAGMA temp_store = MEMORY;";
			sqlCommand.ExecuteNonQuery();

			sqlCommand.CommandText = @"INSERT INTO nodes(nodeId,lat,lon) VALUES(:nodeId,:lat,:lon)";
			sqlCommand.Parameters.Add(new SQLiteParameter("nodeId", System.Data.DbType.Int64));
			sqlCommand.Parameters.Add(new SQLiteParameter("lat", System.Data.DbType.Double));
			sqlCommand.Parameters.Add(new SQLiteParameter("lon", System.Data.DbType.Double));
			sqlCommand.Prepare();


			sqlCommand3 = new SQLiteCommand(sqlConnection);
			sqlCommand3.CommandText = @"INSERT INTO waysData(wayId,wayType,wayString,waySubType) values(@id,@type,@string,@subtype)";
			sqlCommand3.Parameters.Add(new SQLiteParameter("@id", System.Data.DbType.Int64));
			sqlCommand3.Parameters.Add(new SQLiteParameter("@type", System.Data.DbType.Int32));
			sqlCommand3.Parameters.Add(new SQLiteParameter("@string", System.Data.DbType.StringFixedLength));
			sqlCommand3.Parameters.Add(new SQLiteParameter("@subtype", System.Data.DbType.Int32));
			sqlCommand3.Prepare();

			sqlCommand4 = new SQLiteCommand(sqlConnection);
			sqlCommand4.CommandText = @"INSERT INTO waysNodes(wayId,nodeOrder,nodeId) values(@id,@nodeOrder,@nodeId)";
			sqlCommand4.Parameters.Add(new SQLiteParameter("@id", System.Data.DbType.Int64));
			sqlCommand4.Parameters.Add(new SQLiteParameter("@nodeOrder", System.Data.DbType.Int32));
			sqlCommand4.Parameters.Add(new SQLiteParameter("@nodeId", System.Data.DbType.Int64));
			sqlCommand4.Prepare();



			sqlCommand2 = new SQLiteCommand(sqlConnection);
			sqlCommand2.CommandType = System.Data.CommandType.Text;
			//sqlCommand2.CommandText = String.Format("INSERT INTO ways(wayId,wayStartId,wayEndId) values({0},{1},{2})", wayId, firstNode, lastNode);
			sqlCommand2.CommandText = "INSERT INTO ways(wayId,wayStartId,wayEndId,lod) values(@id, @firstNode, @lastNode,@lod)";
			sqlCommand2.Parameters.Add(new SQLiteParameter("@id", System.Data.DbType.Int64));
			sqlCommand2.Parameters.Add(new SQLiteParameter("@firstNode", System.Data.DbType.Int64));
			sqlCommand2.Parameters.Add(new SQLiteParameter("@lastNode", System.Data.DbType.Int64));
			sqlCommand2.Parameters.Add(new SQLiteParameter("@lod", System.Data.DbType.Int32));
			sqlCommand2.Prepare();


			sqlCommand5 = new SQLiteCommand(sqlConnection);
			//sqlCommand5.CommandText = "SELECT min(lat),max(lat),min(lon),max(lon) FROM waysNodes wn LEFT join nodes n ON wn.nodeId=n.nodeId WHERE wn.wayId=@wayId";
			//sqlCommand5.CommandText = "SELECT wn.wayId, min(lat),max(lat),min(lon),max(lon) FROM waysNodes wn LEFT join nodes n ON wn.nodeId=n.nodeId";
			sqlCommand5.CommandText = "INSERT INTO waysBounds(wayId,latStart,latEnd,lonStart,lonEnd) SELECT wn.wayId, min(lat),max(lat),min(lon),max(lon) FROM waysNodes wn LEFT join nodes n ON wn.nodeId=n.nodeId WHERE wayId=@wayId";
			sqlCommand5.Parameters.Add("@wayId", System.Data.DbType.Int64);
			sqlCommand5.Prepare();
			List<Int64> ways = new List<Int64>();



			XPathDocument xpd = new XPathDocument(source);
			XPathNavigator xpn = xpd.CreateNavigator();
			XPathNodeIterator xpni = xpn.Select("/osm/node");
			long k = 0;
			while (xpni.MoveNext())
			{
				k++;
				double lat = Convert.ToDouble(xpni.Current.GetAttribute("lat", ""));
				double lon = Convert.ToDouble(xpni.Current.GetAttribute("lon", ""));

				string id = xpni.Current.GetAttribute("id", "");
				Int64 idLong = Convert.ToInt64(id);
				sqlCommand.Parameters [0].Value = idLong;
				sqlCommand.Parameters [1].Value = lat;
				sqlCommand.Parameters [2].Value = lon;
				try
				{
					sqlCommand.ExecuteNonQuery();
				}
				catch (SQLiteException)
				{
				}

			}


			sqlCommand.Dispose();
			sqlCommand = new SQLiteCommand(sqlConnection);
			sqlCommand.CommandText = "PRAGMA temp_store = MEMORY;";
			sqlCommand.ExecuteNonQuery();

			sqlCommand.CommandText = @"INSERT INTO neighbors(nodeId,neighborId) VALUES(:nodeId,:neighborId)";
			sqlCommand.Parameters.Add(new SQLiteParameter("nodeId", System.Data.DbType.Int64));
			sqlCommand.Parameters.Add(new SQLiteParameter("neighborId", System.Data.DbType.Int64));
			sqlCommand.Prepare();


			XPathNodeIterator xpni2 = xpn.Select("/osm/way");

			while (xpni2.MoveNext())
			{

				string wayId = xpni2.Current.GetAttribute("id", "");
				Int64 wayIdLong = Convert.ToInt64(wayId);
				ways.Add(wayIdLong);
				int wayType = -1;
				int waySubType = -1;
				string wayString = "";
				int lod = -1;


				XPathNodeIterator xpni4 = xpni2.Current.SelectChildren("tag", "");
				while (xpni4.MoveNext())
				{
					//http://wiki.openstreetmap.org/wiki/Beginners_Guide_1.4.1
					string key = xpni4.Current.GetAttribute("k", "");
					string val = xpni4.Current.GetAttribute("v", "");
					switch (key)
					{
						case "highway":
							wayType = 1;
							if (lods.ContainsKey(val))
							{
								lod = lods [val];
							}
							else
							{
								lod = -1;
							}
							if (wTypes.ContainsKey(val))
							{
								waySubType = wTypes [val];
							}
							else
							{
								waySubType = -1;
							}
							break;
						case "ref":
							wayString = val;
							break;
						case "name":
							wayString = val;
							break;
					}
				}





				XPathNodeIterator xpni3 = xpni2.Current.SelectChildren("nd", "");
				Int32 nodesCount = xpni3.Count;

				//Console.WriteLine(nodesCount);

				Int64 refNode = -1;
				Int64 prevRefNode = -1;

				long firstNode = -1;
				int nodeOrder = 0;

				while (xpni3.MoveNext())
				{
					prevRefNode = refNode;
					refNode = Convert.ToInt64(xpni3.Current.GetAttribute("ref", ""));

					sqlCommand4.Parameters [0].Value = wayId;
					sqlCommand4.Parameters [1].Value = nodeOrder++;
					sqlCommand4.Parameters [2].Value = refNode;
					try
					{
						sqlCommand4.ExecuteNonQuery();
					}
					catch (SQLiteException)
					{
					}

					if (firstNode < 0)
					{
						firstNode = refNode;
					}
					if (prevRefNode > 0)
					{
						sqlCommand.Parameters [0].Value = prevRefNode;
						sqlCommand.Parameters [1].Value = refNode;
						try
						{
							sqlCommand.ExecuteNonQuery();
						}
						catch { }
					}
				}


				long lastNode = refNode;
				if (lastNode != firstNode) //not loop (area)
				{

					sqlCommand2.Parameters [0].Value = wayId;
					sqlCommand2.Parameters [1].Value = firstNode;
					sqlCommand2.Parameters [2].Value = lastNode;
					sqlCommand2.Parameters [3].Value = lod;
					try
					{
						sqlCommand2.ExecuteNonQuery();
					}
					catch (SQLiteException)
					{
					}

					sqlCommand3.Parameters [0].Value = wayId;
					sqlCommand3.Parameters [1].Value = wayType;
					sqlCommand3.Parameters [2].Value = wayString;
					sqlCommand3.Parameters [3].Value = waySubType;
					try
					{
						sqlCommand3.ExecuteNonQuery();
					}
					catch (SQLiteException)
					{
					}
				}

			}





			t.Commit();





			//update ways
			t = sqlConnection.BeginTransaction();
			//sqlCommand5
			foreach (Int64 wayId in ways)
			{
				sqlCommand5.Parameters [0].Value = wayId;
				try
				{
					sqlCommand5.ExecuteNonQuery();
				}
				catch (SQLiteException)
				{
				}


			}


			t.Commit();






		}



		Dictionary<string, Dictionary<string, int>> tagz = new Dictionary<string, Dictionary<string, int>>();
		private int GetTag(string key, string value)
		{

			List<string> noStoretags = new List<string>();
			noStoretags.Add("ref");
			noStoretags.Add("name");


			if (noStoretags.Contains(key))
			{
				return -1;
			}

			if (tagz.ContainsKey(key))
			{

				if (tagz [key].ContainsKey(value))
				{
					return tagz [key] [value];
				}
				else
				{
					tagz [key].Add(value, 0);
				}
			}
			else
			{
				tagz.Add(key, new Dictionary<string, int>());
			}


			SQLiteConnection sqlConnection;
			SQLiteCommand sqlCommand;
			sqlConnection = new SQLiteConnection(@"Data Source=G:\gps\gps.sqlite;Pooling=true;FailIfMissing=false");
			sqlCommand = new SQLiteCommand(sqlConnection);
			sqlCommand.CommandType = System.Data.CommandType.Text;
			sqlCommand.CommandText = String.Format("SELECT tagId FROM tags where key='{0}' AND value='{1}'", key, value);
			sqlConnection.Open();

			SQLiteDataReader sdr = sqlCommand.ExecuteReader();
			while (sdr.Read())
			{
				tagz [key] [value] = sdr.GetInt32(0);
			}
			sdr.Close();
			sdr.Dispose();
			return tagz [key] [value];


		}


		



	}
}
